#include "fs.h"
#include <string.h>
#include "process.h"
#include "dbgio.h"

uint32_t read_fs(struct vfs_node *node ,uint8_t *buffer ,uint32_t offset ,uint32_t length,uint32_t fflags){
	if(node->read == 0)
		return 0;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	return node->read(node,buffer,offset,length,fflags);
}

uint32_t write_fs(struct vfs_node *node ,uint8_t *buffer ,uint32_t offset ,uint32_t length,uint32_t fflags){
	if(node->write == 0)
		return 0;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	return node->write(node,buffer,offset,length,fflags);
}

void open_fs(struct vfs_node *node){
	if(node->open == 0)
		return;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	return node->open(node);
}

void close_fs(struct vfs_node *node){
	if(node->close == 0)
		return;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	node->close(node);
}

struct vfs_node * finddir_fs(struct vfs_node *node,char *name){
	if(node->finddir == 0)
		return (vfs_node *) 0;
	if ((node->flags & VFS_DIRECTORY_FLAG) == 0)
		return (vfs_node *) 0;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	if (strcmp(name,"..")==0)
		return node->parent;
	if (strcmp(name,".")==0)
		return node;
	return node->finddir(node,name);
}

struct vfs_node * touch_fs(struct vfs_node *node,char *name,uint32_t mode){
	//dprintf("Node 0x%x %s\n",node,name);
	if(node->finddir == 0)
		return (vfs_node *) 0;
	if ((node->flags & VFS_DIRECTORY_FLAG) == 0)
		return (vfs_node *) 0;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	//dprintf("Node 0x%x %s\n",node,name);
	return node->touch(node,name,mode);
}

struct vfs_node * mkdir_fs(struct vfs_node *node,char *name,uint32_t mode){
	if(node->finddir == 0)
		return (vfs_node *) 0;
	if ((node->flags & VFS_DIRECTORY_FLAG) == 0)
		return (vfs_node *) 0;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	return node->mkdir(node,name,mode);
}

struct vfs_dir * readdir_fs(struct vfs_node *node,uint32_t id){
	if(node->readdir == 0)
		return (vfs_dir *) 0;
	if ((node->flags & VFS_DIRECTORY_FLAG) == 0)
		return (vfs_dir *) 0;
	if (((node->flags & (VFS_MOUNTPOINT_FLAG | VFS_SYMLINK_FLAG)) != 0) && (node->ptr != 0))//Used for symlinks and mount points
		node = node->ptr;
	return node->readdir(node,id);
}

vfs_node_t *touch_rc_fs(vfs_node_t *parent,char *path,uint32_t mode){
//	dprintf("Creating sub file of %s named %s\n",parent->filename,path);
	 char *tok_a;
	 char *tok_b;
	 char *work = path;
	 if (work[0] == '/'){
		 parent = get_current_process()->root_directory;
		work = &work[1];
	 } else if (parent == 0){
		 parent = get_current_process()->current_directory;
	 }
	 tok_a = strtok(work,"/");
	 while (1){
		 tok_b = strtok((char *)0,"/");
//		 dprintf("Recurse : %s %s\n",tok_a,tok_b);
		 if (tok_b == (char *) 0){
			 return touch_fs(parent,tok_a,mode);
		 } else {
			 if (finddir_fs(parent,tok_a) == (vfs_node_t *)0)
				parent = mkdir_fs(parent,tok_a,0x1FF);
			 else
				parent = finddir_fs(parent,tok_a);
		 }
		 tok_a = tok_b;
	 }
}
vfs_node_t *mkdir_rc_fs(vfs_node_t *parent,char *path,uint32_t mode){
	 char *tok_a;
	 char *tok_b;
	 char *work = path;
	 if (work[0] == '/'){
		 parent = get_current_process()->root_directory;
		work = &work[1];
	 } else if (parent == 0){
		 parent = get_current_process()->current_directory;
	 }
	 tok_a = strtok(work,"/");
	 while (1){
		 tok_b = strtok((char *)0,"/");
		 if (tok_b == (char *)0){
			 if (finddir_fs(parent,tok_a) == (vfs_node_t *)0)
				return mkdir_fs(parent,tok_a,mode);
			 else
				return finddir_fs(parent,tok_a);
		 } else {
			 if (finddir_fs(parent,tok_a) == (vfs_node_t *)0)
				parent = mkdir_fs(parent,tok_a,0xFF);
			 else
				parent = finddir_fs(parent,tok_a);
		 }
		 tok_a = tok_b;
	 }
}

vfs_node_t *finddir_rc_fs(vfs_node_t *parent,char *path){
	 char *tok_a;
	 char *tok_b;
	 char *work = path;
	 if (work[0] == '/'){
		 parent = get_current_process()->root_directory;
		work = &work[1];
	 } else if (parent == 0){
		 parent = get_current_process()->current_directory;
	 }
	 tok_a = strtok(work,"/");
	 if (tok_a == (char *)0)
		 return parent;
	 while (1){
		 if (parent == (vfs_node_t *)0)
			 return 0;
		 tok_b = strtok((char *)0,"/");
		 if (tok_b == (char *)0){
			 return finddir_fs(parent,tok_a);
		 } else {
			 parent = finddir_fs(parent,tok_a);
		 }
		 tok_a = tok_b;
	 }
}

void get_path(vfs_node_t *node,char *dest){
	char buf[512];
	char append[512];
	strcpy(buf,"/");
	while(1){
		if (node == get_current_process()->root_directory){
			strcpy(append,"/");
			strcat(append,dest);
			strcpy(dest,append);
			break;
		} else {			
			strcpy(append,node->name);
			strcat(append,dest);
		}
		//append = filename + previous
		strcat(buf,append);
		//buf = "/" + filename + previous
		strcpy(dest,buf);
		strcpy(buf,"/");
		node = node->parent;
	}
	if (strlen(dest) == 1)
		strcpy(dest,"/");
}

void chroot_fs(vfs_node_t *root){
	get_current_process()->root_directory = root;
	get_current_process()->current_directory = root;
}
